package webshop.model.bl;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.ResultTransformer;

import webshop.model.db.Category;
import webshop.model.db.Product;
import webshop.model.sf.HibernateUtil;

public class ProductManager {

	public void saveProduct(Product product) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		session.save(product);
		
		session.getTransaction().commit();
	}
	
	public List<Product> getAllProducts() {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		@SuppressWarnings("unchecked")
		List<Product> products = session.createCriteria(Product.class).list();
		
		session.getTransaction().commit();
		
		return products;
	}
	
	public Product getProductById(int productId) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		
		@SuppressWarnings("unchecked")
		List<Product> productList = session.createCriteria(Product.class).add(
				Restrictions.eq("productId", productId)
				).list();
		
		session.getTransaction().commit();
		
		return productList == null || productList.size() == 0 ? null : productList.get(0);
	}
	
	public boolean productExists(String productName) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		@SuppressWarnings("unchecked")
		List<Product> productList = session.createCriteria(Product.class).add(
				Restrictions.eq("name", productName).ignoreCase()
				).list();
		
		session.getTransaction().commit();
		
		return productList == null || productList.size() == 0 ? false : true;
	}
	
	public void deleteProduct(int productId) {
		Product p = getProductById(productId);
		if (p == null) {
			return;
		}
		
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		
		session.delete(p);
		
		session.getTransaction().commit();
	}

	public List<Category> searchForProduct(String searchFor, int categoryId, String searchIn) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		
		session.beginTransaction();
		Criteria search = session.createCriteria(Product.class)
				.add(Restrictions.like(searchIn, "%" + searchFor + "%").ignoreCase())
				.setResultTransformer(new ProductToCategoryTransformer())
				.createCriteria("category", "c");
		if (categoryId != -1) {
			search.add(Restrictions.eq("c.categoryId", categoryId));
		}
		
		@SuppressWarnings("unchecked")
		List<Category> categoryList = search.list();
		
		session.getTransaction().commit();
		return categoryList;
	}
	
	private class ProductToCategoryTransformer implements ResultTransformer {
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 3065506714041894068L;
		
		@Override
		@SuppressWarnings("rawtypes")
		public List transformList(List arg0) {			
			@SuppressWarnings("unchecked")
			List<Product> products = arg0;
			
			List<Category> categoryList = new LinkedList<Category>();
			Map<Integer, Category> categoryMap = new HashMap<Integer, Category>();
			
			for (Product p : products) {
				Category c = categoryMap.get(p.getCategory().getCategoryId());
				if (c == null) {
					c = new Category();
					c.setCategoryId(p.getCategory().getCategoryId());
					c.setName(p.getCategory().getName());
					c.setProducts(new LinkedHashSet<Product>());
					categoryList.add(c);
					categoryMap.put(p.getCategory().getCategoryId(), c);
				}
				c.getProducts().add(p);
			}
			
			return categoryList;
		}

		@Override
		public Object transformTuple(Object[] arg0, String[] arg1) {
			Product p = (Product) arg0[1];
			p.setCategory((Category) arg0[0]);
			return p;
		}
		
	}
	
}
